package service;

import java.util.List;

import util.CheckParameters;
import util.Utils;
import dao.PaymentDAO;
import domain.Balance;
import domain.Payment;
import domain.Roommate;
import exception.InvalidBusinessStateException;

public class PaymentService extends GenericService<Payment> {

	private static PaymentService instance;
	
	public static PaymentService getInstance() {
		if (instance == null)
			instance = new PaymentService();
		return instance;
	}
	
	public PaymentService() {
		dao = PaymentDAO.getInstance();
	}

	@Override
	protected void businessRules(Payment payment)
			throws InvalidBusinessStateException {
		CheckParameters.checkStringEmpty(payment.getDescription(), "Payment's description");
		CheckParameters.checkPositive(payment.getAmount(), "Payment's amount");
		CheckParameters.checkNull(payment.getBalanceMonth(), "Current reference balance");
		CheckParameters.checkNotEmptyCollection(payment.getParticipants(), "List of participants");
		CheckParameters.checkNull(payment.getAuthor(), "Author of the payment");
	}

	@Override
	protected void handleDependencies(Payment entity)
			throws InvalidBusinessStateException {
		if (entity.getId() != null) {
			cascadeDeletion(entity.getId());
		}
		double amountToAdd = Utils.findDividableAmount(entity.getAmount(), entity.getParticipants().size());
		//find amount to add to each balance
		amountToAdd /= (double) entity.getParticipants().size();
		//for each participants, add amount to balance
		for (Roommate roommate : entity.getParticipants()) {
			Balance balance = BalanceService.getInstance().findByRoommate(roommate.getId());
			balance.plus(amountToAdd);
			//if current balance is payment's author's balance, substract the whole amount from his balance
			if (balance.getRoommate().equals(roommate)) {
				balance.subtract(entity.getAmount());
			}
			//update balance
			BalanceService.getInstance().update(balance);
		}
	}

	@Override
	protected void cascadeDeletion(Integer id) throws InvalidBusinessStateException {
		Payment entity = find(id);
		double amountToSubtract = Utils.findDividableAmount(entity.getAmount(), entity.getParticipants().size());
		//find amount to substract from each balance
		amountToSubtract /= (double) entity.getParticipants().size();
		//for each participants, substract amount from balance
		for (Roommate roommate : entity.getParticipants()) {
			Balance balance = BalanceService.getInstance().findByRoommate(roommate.getId());
			// add a negative amount is the same as substracting a positive number oright? now shut up
			balance.subtract(amountToSubtract);
			//if current balance is payment's author's balance, add the whole amount to his balance
			if (balance.getRoommate().equals(roommate)) {
				balance.plus(entity.getAmount());
			}
			//update balance
			BalanceService.getInstance().update(balance);
		}
	}

	public List<Payment> getAllByBalanceMonth(Integer id) {
		return ((PaymentDAO) dao).getAllByBalanceMonth(id);
	}

}
